package com.fubowen.reader.extension


import android.content.Context
import android.graphics.BitmapFactory
import com.squareup.moshi.Moshi
import okhttp3.MediaType.Companion.toMediaType
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.RequestBody.Companion.toRequestBody
import okhttp3.Response
import java.util.concurrent.TimeUnit


const val AGENT = "Mozilla/5.0 (Linux; Android 11; Pixel 5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.210 Mobile Safari/537.36"
const val TIMEOUT = 30000L
const val FAVICON_ICO = "/favicon.ico"

val httpClient: OkHttpClient by lazy {
    OkHttpClient.Builder().readTimeout(TIMEOUT, TimeUnit.MILLISECONDS).build()
}

fun fetchGet(url: String) = httpClient.newCall(Request.Builder().url(url).get().build()).execute()
inline fun <reified T> fetchPost(url: String, data: T): Response {
    val moshi = Moshi.Builder().build()
    val adapter = moshi.adapter(T::class.java)
    val mediaType = "application/json;charset=utf-8".toMediaType()
    val json = adapter.toJson(data).toRequestBody(mediaType)
    val request = Request.Builder()
        .addHeader("Content-Type", "application/json")
        .url(url)
        .post(json)
        .build()
    return httpClient.newCall(request).execute()
}

fun downloadImage(context: Context, url: String, filePath: String): String? {
    val path = context.externalCacheDir!!.absolutePath + filePath
    fetchGet(url).use { response ->
        if (response.isSuccessful) {
            response.body.byteStream().use {
                val bitmap = BitmapFactory.decodeStream(it)
                return bitmap.saveBitmapToFile(path)
            }
        }
    }
    return null
}

fun favicon(base: String): ByteArray {
    val favicon = "https://www.xiaohongshu.com//favicon.ico"//url + if (url.endsWith("/")) "favicon.ico" else "/favicon.ico"
    return fetchGet(favicon).body.bytes()
}

fun <T> retry(options: Options, block: () -> T): T? {
    for (i in 0 until options.tryCount) {
        try {
            return block()
        } catch (e: Exception) {
            val dd = e.message
        }
    }
    return null
}

fun <T> retryOrThrow(options: Options, block: () -> T): T {
    val exception = mutableListOf<Exception>()
    for (i in 0 until options.tryCount) {
        try {
            return block()
        } catch (e: Exception) {
            exception.add(e)
        }
    }
    throw exception.last()
}

inline fun <reified T> Response.toObject(): T? {
    val moshi = Moshi.Builder().build()
    return moshi.adapter(T::class.java).fromJson(this.body.string())
}

data class Options(
    var tryCount: Int = 3,
    var timeout: Long = TIMEOUT,
    var agent: String = AGENT
)

